#MySQL SQL转换

本文档基于MySQL8.0已有语法,根据SQL转换对以下语法进行了规则化的转换。

# 概述

在YMP的任务评估阶段,会对源数据库中的对象(表、视图、约束、索引等)进行兼容性评估,以确保源端数据库对象可以成功迁移到目标数据库。在评估阶段,会尝试获取源端数据库对象的DDL并在目标数据库执行。如果执行成功,则说明此对象为原生兼容,无需进行特殊处理。否则,会使用SQL转换工具根据源端到目标端数据库的语法转换规则对此DDL进行语法转换,以适配目标数据库的语法特性。如果转换成功,会尝试在目标数据库中执行转换后的SQL,执行成功则说明此对象为自动兼容,可以进行迁移。

# CREATE TABLE

序号 MySQL语法/关键字 YashanDB22.2转换规则 YashanDB23.1转换规则
1 临时表TEMPORARY关键字 转为全局临时表 同左
2 create_definition: {
col_name column_definition
| {INDEX | KEY} [index_name] [index_type] (key_part,...)
[index_option] ... (表内索引)
| {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...)
[index_option] ...
| [CONSTRAINT [symbol]] PRIMARY KEY (表内主键)
[index_type] (key_part,...)
[index_option] ...
| [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY] (索引定义)
[index_name] [index_type] (key_part,...)
[index_option] ...
| [CONSTRAINT [symbol]] FOREIGN KEY (外键引用定义)
[index_name] (col_name,...)
reference_definition (外键引用定义)
| check_constraint_definition
}
只保留col_name column_definition 同左
3 column_definition: {
data_type [NOT NULL | NULL]
[VISIBLE | INVISIBLE]
[AUTO_INCREMENT] [UNIQUE [KEY]] [[PRIMARY] KEY]
[COMMENT 'string'] (列注释信息)
[COLLATE collation_name]
[COLUMN_FORMAT {FIXED | DYNAMIC | DEFAULT}]
[ENGINE_ATTRIBUTE [=] 'string']
[SECONDARY_ENGINE_ATTRIBUTE [=] 'string']
[STORAGE {DISK | MEMORY}]
[reference_definition]
[check_constraint_definition]
| data_type
[COLLATE collation_name]
[GENERATED ALWAYS] AS (expr)
[VIRTUAL | STORED] [NOT NULL | NULL]
[VISIBLE | INVISIBLE]
[UNIQUE [KEY]] [[PRIMARY] KEY]
[COMMENT 'string']
[reference_definition]
[check_constraint_definition]
}
只保留data_type,和DEFAULT 。
AUTO_INCREMENT和comment语法会转化为单独的语句,分别跟随在表定义前和后。
注:仅部分数据类型可以正常转出。
同左
4 table_option: {
AUTOEXTEND_SIZE [=] value
| AUTO_INCREMENT [=] value
| AVG_ROW_LENGTH [=] value
| [DEFAULT] CHARACTER SET [=] charset_name
| CHECKSUM [=] {0 | 1}
| [DEFAULT] COLLATE [=] collation_name
| COMMENT [=] 'string'
| COMPRESSION [=] {'ZLIB' | 'LZ4' | 'NONE'}
| CONNECTION [=] 'connect_string'
| {DATA | INDEX} DIRECTORY [=] 'absolute path to directory'
| DELAY_KEY_WRITE [=] {0 | 1}
| ENCRYPTION [=] {'Y' | 'N'}
| ENGINE [=] engine_name
| ENGINE_ATTRIBUTE [=] 'string'
| INSERT_METHOD [=] { NO | FIRST | LAST }
| KEY_BLOCK_SIZE [=] value
| MAX_ROWS [=] value
| MIN_ROWS [=] value
| PACK_KEYS [=] {0 | 1 | DEFAULT}
| PASSWORD [=] 'string'
| ROW_FORMAT [=] {DEFAULT | DYNAMIC | FIXED | COMPRESSED | REDUNDANT | COMPACT}
| START TRANSACTION
| SECONDARY_ENGINE_ATTRIBUTE [=] 'string'
| STATS_AUTO_RECALC [=] {DEFAULT | 0 | 1}
| STATS_PERSISTENT [=] {DEFAULT | 0 | 1}
| STATS_SAMPLE_PAGES [=] value
| tablespace_option
| UNION [=] (tbl_name[,tbl_name]...)
}
AUTO_INCREMENT [=] value会换为表前定义序列的start with的起始值。

COMMENT [=] 'string'会转为表后的单独comment语句



tablespace_option初始获取可能会带有注释形式,移除注释(YMP处理),tablespace正常转换出来(保留名字)。
同左
5 tablespace_option:
TABLESPACE tablespace_name [STORAGE DISK]
| [TABLESPACE tablespace_name] STORAGE MEMORY
只保留表空间名称,删除[STORAGE DISK]

如果表空间名称为innodb_file_per_table,则表示为默认表空间,因此转换时会丢弃表空间名称信息
同左
6 partition_definition:
PARTITION partition_name 分区定义语法
[VALUES
{LESS THAN {(expr | value_list) | MAXVALUE}
|
IN (value_list)}]
[[STORAGE] ENGINE [=] engine_name]
[COMMENT [=] 'string' ]
[DATA DIRECTORY [=] 'data_dir']
[INDEX DIRECTORY [=] 'index_dir']
[MAX_ROWS [=] max_number_of_rows]
[MIN_ROWS [=] min_number_of_rows]
[TABLESPACE [=] tablespace_name]
[(subpartition_definition [, subpartition_definition] ...)]
只保留YashanDB支持的分区定义信息,

[[STORAGE] ENGINE [=] engine_name]
[COMMENT [=] 'string' ]
[DATA DIRECTORY [=] 'data_dir']
[INDEX DIRECTORY [=] 'index_dir']
[MAX_ROWS [=] max_number_of_rows]
[MIN_ROWS [=] min_number_of_rows]

都会被删除

分区信息初始获取可能会带有注释形式,移除注释(YMP处理)
同左
7 subpartition_definition: 子分区定义语法

SUBPARTITION logical_name

[[STORAGE] ENGINE [=] engine_name]

[COMMENT [=] 'string' ]

[DATA DIRECTORY [=] 'data_dir']

[INDEX DIRECTORY [=] 'index_dir']

[MAX_ROWS [=] max_number_of_rows]

[MIN_ROWS [=] min_number_of_rows]

[TABLESPACE [=] tablespace_name]
22.2无该语法 ,转换时删除 23.1保留子分区转换输出
8 ON UPDATE CURRENT_TIMESTAMP(n) 转换成触发器 同左

# CREATE VIEW

序号 MySQL语法/关键字 YashanDB22.2转换规则 YashanDB23.1转换规则
9 CREATE
[OR REPLACE]
[SQL SECURITY { DEFINER | INVOKER }]
VIEW view_name [(column_list)]
AS
[SQL SECURITY { DEFINER | INVOKER }] 删除 同左
10 [WITH [CASCADED | LOCAL] CHECK OPTION] 全部删除 同左
11 SELECT 子查询 保持语义输出 同左

# CREATE INDEX

序号 MySQL语法/关键字 YashanDB22.2转换规则 YashanDB23.1转换规则
12 CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name 仅支持UNIQUE类型和普通类型 同左
13 index_option: {
KEY_BLOCK_SIZE [=] value
| index_type
| WITH PARSER parser_name
| COMMENT 'string'
| {VISIBLE | INVISIBLE}
| ENGINE_ATTRIBUTE [=] 'string'
| SECONDARY_ENGINE_ATTRIBUTE [=] 'string'
}

index_type:
USING {BTREE | HASH}

algorithm_option:
ALGORITHM [=] {DEFAULT | INPLACE | COPY}

lock_option:
LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}
全部删除 同左

# ALTER TABLE ADD CONSTRAINT / MODIFY NOT NULL

序号 MySQL语法/关键字 YashanDB22.2转换规则 YashanDB23.1转换规则
14 [CONSTRAINT [symbol]] PRIMARY KEY

[index_type] (key_part,...)

[index_option] ...
删除index_type 和index_option 同左
15 ADD [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY]
[index_name] [index_type] (key_part,...)
[index_option] ...
删除index_type 和index_option 同左
16 ADD [CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (col_name,...)
reference_definition
一致 同左
17 ADD [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED] 删除[[NOT] ENFORCED] 同左
18 MODIFY COLUMN_NAME DATATYPE NOT NULL 删除DATATYPE 同左

# CREATE EVENT

MySQL的Event对应对象为YashanDB的JOB,通过查询information_schema.EVENTS视图,将所需要的关键信息进行组装拼接成YashanDB的JOB的创建语句。 所使用到information_schema.EVENTS的关键字段和含义如下表所示。

EVENT_SCHEMA EVENT_NAME EVENT_DEFINITION EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STARTS ENDS STATUS ON_COMPLETION EVENT_COMMENT
Event所属Schema Event名称 Event要执行的SQL语句 event类型 (循环/单词) 执行时间 执行间隔值 执行间隔时间的单位 该event开始起作用的时间 该event结束起作用的时间 对象状态 完成后是否被删除 对象的COMMENT信息

对上面的关键信息进行拼接,就可以获取对应的YashanDB的JOB创建语句,YashanDB的JOB创建语句样式如下:

EXEC DBMS_SCHEDULER.CREATE_JOB (
    job_name IN VARCHAR,   -- 对应字段  EVENT_NAME
    job_type IN VARCHAR,    -- 对应字段  EVENT_TYPE
    job_action IN VARCHAR , -- 对应字段   begin  EVENT_DEFINITION end ;
    number_of_arguments IN INTEGER DEFAULT 0,   -- 无对应字段  保留字段,使用缺省值 0。
    start_date IN TIMESTAMP DEFAULT NULL,   -- 对应字段    STARTS /  EXECUTE_AT
    repeat_interval IN VARCHAR DEFAULT NULL,    -- 对应字段 INTERVAL_VALUE INTERVAL_FIELD
    end_date IN TIMESTAMP DEFAULT NULL, -- 对应字段   ENDS
    job_class IN VARCHAR DEFAULT 'DEFAULT_JOB_CLASS',   -- 无对应字段  保留字段,使用缺省值   'DEFAULT_JOB_CLASS'。
    enabled IN BOOLEAN DEFAULT FALSE,   -- 对应字段  STATUS
    auto_drop IN BOOLEAN DEFAULT TRUE,  -- 对应字段   ON_COMPLETION
    comments IN VARCHAR DEFAULT NULL);  -- 对应字段  EVENT_COMMENT
Copied!

示例19展示了一个MySQL的Event转换为YashanDB的JOB的样例。

# PLSQL对象处理

对象类型 规则 MySQL语法 YashanDB预期
触发器 CREATE [DEFINER = user] TRIGGER [IF NOT EXISTS] sp_name CREATE or replace TRIGGER "SP_NAME"
函数 CREATE [DEFINER = user] FUNCTION [IF NOT EXISTS] sp_name CREATE or replace FUNCTION "SP_NAME"
存储过程 CREATE [DEFINER = user] PROCEDURE [IF NOT EXISTS] sp_name CREATE or replace PROCEDURE "SP_NAME"
对象名左右两边 | 替换为" 且内部转大写 | ```sql create tablexxx(id` int );|sql create table "XXX" ("ID" int );```

# 全部示例

# 示例1

 -- MySQL
 CREATE TEMPORARY TABLE x(id INT)
 -- YashanDB22.2预期结果
 CREATE GLOBAL TEMPORARY TABLE "X" ("ID" INT);
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例2

 -- MySQL
 CREATE TABLE MYL.TEST4 (col1 INT REFERENCES MYL.T2(col1) ON
    DELETE
    SET
    null,
    col2 INT DEFAULT 1 CHECK(col2 < 30));
 -- YashanDB22.2预期结果
 CREATE TABLE "MYL"."TEST4" (
    "COL1" INT,
    "COL2" INT DEFAULT 1
);
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例3

 -- MySQL
CREATE TABLE x(id INT auto_increment DEFAULT 'xxx' COMMENT 'xxx');
 -- YashanDB22.2预期结果
 CREATE SEQUENCE "X_ID_SEQ" INCREMENT BY 1 START WITH 1;
CREATE TABLE "X" (
    "ID" INT DEFAULT 'xxx' DEFAULT "X_ID_SEQ".NEXTVAL
);
 
COMMENT ON COLUMN "X"."ID" IS 'xxx';
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例4

 -- MySQL
CREATE TABLE x(id INT auto_increment DEFAULT 'xxx' COMMENT 'xxx') COMMENT 'xxx' auto_increment = 1231 TABLESPACE xxx STORAGE DISK;
 -- YashanDB22.2预期结果
 CREATE SEQUENCE "X_ID_SEQ" INCREMENT BY 1 START WITH 1231;
CREATE TABLE x (
    "ID" INT DEFAULT 'xxx' DEFAULT "X_ID_SEQ".NEXTVAL
) TABLESPACE "XXXDISK";
 
COMMENT ON COLUMN "X"."ID" IS 'xxx';
COMMENT ON TABLE "X" IS 'xxx';
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例5

 -- MySQL
 CREATE TABLE x(id INT auto_increment DEFAULT 'xxx' COMMENT 'xxx') COMMENT 'xxx' auto_increment = 1231 TABLESPACE xxx STORAGE DISK;
 -- YashanDB22.2预期结果
 CREATE SEQUENCE "X_ID_SEQ" INCREMENT BY 1 START WITH 1231;
CREATE TABLE "x" (
    "ID" INT DEFAULT 'xxx' DEFAULT "X_ID_SEQ".NEXTVAL
) TABLESPACE "XXXDISK";
 
COMMENT ON COLUMN "X"."ID" IS 'xxx';
COMMENT ON TABLE "X" IS 'xxx';
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例6

 -- MySQL
 	
CREATE TABLE th (id INT, name VARCHAR(30), adate DATE)
PARTITION BY LIST(YEAR(adate))
(
  PARTITION p1999 VALUES IN (1995, 1999, 2003)
    DATA DIRECTORY = '/var/appdata/95/data'
    INDEX DIRECTORY = '/var/appdata/95/idx',
  PARTITION p2000 VALUES IN (1996, 2000, 2004)
    DATA DIRECTORY = '/var/appdata/96/data'
    INDEX DIRECTORY = '/var/appdata/96/idx' TABLESPACE  xxx,
  PARTITION p2001 VALUES IN (1997, 2001, 2005)
    DATA DIRECTORY = '/var/appdata/97/data'
    INDEX DIRECTORY = '/var/appdata/97/idx',
  PARTITION p2002 VALUES IN (1998, 2002, 2006)
    DATA DIRECTORY = '/var/appdata/98/data'
    INDEX DIRECTORY = '/var/appdata/98/idx'
);
 -- YashanDB22.2预期结果
 CREATE TABLE "TH" (
    "ID" INT,
    "NAME" VARCHAR(30 CHAR),
    "ADATE" DATE
)
PARTITION BY LIST (YEAR("ADATE")) ( PARTITION "P1999" VALUES ((1995), (1999), (2003)) , PARTITION "P2000" VALUES ((1996), (2000), (2004))
    TABLESPACE "XXX", PARTITION "P2001" VALUES ((1997), (2001), (2005)) , PARTITION "P2002" VALUES ((1998), (2002), (2006))
);
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例7

 -- MySQL
 CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE( YEAR(purchased) )
    SUBPARTITION BY HASH( TO_DAYS(purchased) )
    SUBPARTITIONS 2 (
        PARTITION p0 VALUES LESS THAN (1990),
        PARTITION p1 VALUES LESS THAN (2000),
        PARTITION p2 VALUES LESS THAN MAXVALUE
    );
 -- YashanDB22.2预期结果
 CREATE TABLE "TS" (
    "ID" INT,
    "PURCHASED" DATE
)
PARTITION BY RANGE (YEAR("PURCHASED"))
 ( PARTITION "P0" VALUES LESS THAN (1990) , PARTITION "P1" VALUES LESS THAN (2000) , PARTITION "P2" VALUES LESS THAN (MAXVALUE) );
 -- YashanDB23.1预期结果
 CREATE TABLE "TS" (
    "ID" INT,
    "PURCHASED" DATE
)
PARTITION BY RANGE (YEAR("PURCHASED"))
SUBPARTITION BY HASH(TO_DAYS("PURCHASED")) SUBPARTITIONS  2
 ( PARTITION "P0" VALUES LESS THAN (1990) , PARTITION "P0" VALUES LESS THAN (2000) , PARTITION "P2" VALUES LESS THAN (MAXVALUE) );
 -- 同上
Copied!

# 示例8

 -- MySQL
CREATE TABLE `test_timestamp`(
    id INT , 
    t1 TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))
 -- YashanDB22.2预期结果
CREATE TABLE "TEST_TIMESTAMP" (
	"ID" INT,
	"T1" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP()
)
;
CREATE TRIGGER "TEST_TIMESTAMP_T1_TRI"
BEFORE UPDATE ON "TEST_TIMESTAMP"
FOR EACH ROW
 BEGIN
   IF NOT UPDATING('T1')  THEN 
   		:NEW."T1" := CURRENT_TIMESTAMP();
   END IF;
END;/
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例9

 -- MySQL
 CREATE OR replace  VIEW v3 (idalias ) AS SELECT id FROM v1 WHERE a > 0
 -- YashanDB22.2预期结果
 CREATE OR REPLACE VIEW "V3"
AS
SELECT "ID"
FROM "V1"
WHERE "A" > 0;
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例10

 -- MySQL
 CREATE OR replace  VIEW v3 (idalias ) AS SELECT id FROM v1 WHERE a > 0
WITH CASCADED CHECK OPTION;
 -- YashanDB22.2预期结果
 CREATE OR replace  VIEW "V3" ("IDALIAS" ) AS SELECT "ID" FROM "V1" WHERE "A" > 0

 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例12

 -- MySQL
 /*The 1 SQL statement*/
CREATE UNIQUE INDEX xxx ON x(x);
 
/*The 2 SQL statement*/
CREATE FULLTEXT INDEX xxx ON x(x);
 
/*The 3 SQL statement*/
CREATE INDEX xxx ON x(x);

 -- YashanDB22.2预期结果
 /*The 1 SQL statement*/
CREATE UNIQUE INDEX "XXX" ON "X" ("X");
 
/*The 2 SQL statement*/
CREATE  INDEX "XXX" ON "X" ("X");
 
/*The 3 SQL statement*/
CREATE  INDEX "XXX" ON "X" ("X");
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例13

 -- MySQL
 /*The 1 SQL statement*/
CREATE INDEX id_index ON lookup (id) USING BTREE;
 
/*The 2 SQL statement*/
CREATE INDEX id_index ON t1 (id) COMMENT 'MERGE_THRESHOLD=40';

 -- YashanDB22.2预期结果
 /*The 1 SQL statement*/
CREATE INDEX "ID_INDEX" ON "LOOKUP" ("ID");
 
/*The 2 SQL statement*/
CREATE INDEX "ID_INDEX" ON "T1" ("ID");
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例14

 -- MySQL
 ALTER TABLE xx ADD PRIMARY USING BTREE (id);
 -- YashanDB22.2预期结果
 ALTER TABLE "XX" ADD PRIMARY KEY ("ID");
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例15

 -- MySQL
 ALTER TABLE student ADD CONSTRAINT  xx UNIQUE KEY USING BTREE(id)  ;
 -- YashanDB22.2预期结果
 ALTER TABLE "STUDENT" ADD CONSTRAINT "XX" UNIQUE ("ID");
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例17

 -- MySQL
ALTER TABLE student ADD CHECK (id>0) ENFORCED ;
 -- YashanDB22.2预期结果
 ALTER TABLE "STUDENT" ADD CHECK ("ID">0) ;
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例18

 -- MySQL
 ALTER TABLE X MODIFY ID INT NOT NULL;
 -- YashanDB22.2预期结果
 ALTER TABLE "X" MODIFY "ID"  NOT NULL;
 -- YashanDB23.1预期结果
 -- 同上
Copied!

# 示例19

 -- MySQL
 CREATE DEFINER=`root`@`%` EVENT `myevent` 
    ON SCHEDULE AT '2024-01-09 06:14:00' 
    ON COMPLETION PRESERVE DISABLE ON SLAVE 
    DO 
        UPDATE mytable SET mycol = mycol + 1;
    ;   
 -- YashanDB22.2预期结果
 EXEC DBMS_SCHEDULER.CREATE_JOB('LSP.myevent',
    'PLSQL_BLOCK', 
    ' BEGIN UPDATE mytable SET mycol = mycol + 1 ; END ;' ,
    0,
    TO_TIMESTAMP('2024-01-09 06:14:00', 'YYYY-MM-DD HH24:MI:SS'),
    null,
    null,
    'DEFAULT_JOB_CLASS',
    false,
    false,
    null);
 -- YashanDB23.1预期结果
 -- 同上
Copied!